package mqttmodule

import (
	"crypto/tls"
	"fmt"
	"sync"

	mqtt "github.com/eclipse/paho.mqtt.golang"
)

var (
	clientInstance *MQTTClient
	once           sync.Once
)

// MQTTClient 是 MQTT 客户端的封装
type MQTTClient struct {
	client mqtt.Client
}

// GetMQTTClient 返回单例的 MQTTClient 实例
func GetMQTTClient() *MQTTClient {
	return clientInstance
}

// InitializeTLS 初始化 MQTT 客户端并连接到指定的 Broker
func InitializeTLS(broker string, port int, clientID, username, password string) (*MQTTClient, error) {
	once.Do(func() {
		opts := mqtt.NewClientOptions()
		brokerURL := fmt.Sprintf("tls://%s:%d", broker, port) // Use 'tls://' scheme
		opts.AddBroker(brokerURL)
		opts.SetClientID(clientID)
		opts.SetUsername(username)
		opts.SetPassword(password)
		opts.SetDefaultPublishHandler(messagePubHandler)

		// Setup TLS configuration, skipping certificate verification
		tlsConfig := &tls.Config{
			InsecureSkipVerify: true,             // This skips certificate verification (DO NOT use this in production if security is required)
			MinVersion:         tls.VersionTLS12, // Force TLS v1.2
		}
		opts.SetTLSConfig(tlsConfig)

		// Set connection handlers
		opts.OnConnect = func(client mqtt.Client) {
			fmt.Println("Connected to the broker using TLS")
		}
		opts.OnConnectionLost = func(client mqtt.Client, err error) {
			fmt.Printf("Connection lost: %v\n", err)
		}

		// Create and start the MQTT client using the above options
		clientInstance = &MQTTClient{
			client: mqtt.NewClient(opts),
		}
		if token := clientInstance.client.Connect(); token.Wait() && token.Error() != nil {
			fmt.Printf("Failed to connect to broker: %v\n", token.Error())
		} else {
			fmt.Println("MQTT client connected")
		}
	})
	if clientInstance == nil || !clientInstance.client.IsConnected() {
		return nil, fmt.Errorf("failed to initialize and connect to broker")
	}
	return clientInstance, nil
}

// Publish 发送消息到指定的 MQTT 主题
func (m *MQTTClient) Publish(topic, message string, qos byte, retained bool) error {
	token := m.client.Publish(topic, qos, retained, message)
	token.Wait()
	if token.Error() != nil {
		return fmt.Errorf("failed to publish message: %v", token.Error())
	}
	fmt.Printf("Message published to topic %s: %s\n", topic, message)
	return nil
}

// Disconnect 优雅地断开 MQTT 客户端
func (m *MQTTClient) Disconnect() {
	m.client.Disconnect(250)
	fmt.Println("MQTT client disconnected")
}

// messagePubHandler 是一个默认的消息处理程序
var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
	fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())
}
